iT邦幫忙

2022 iThome 鐵人賽

DAY 24
0

今天是最後一次了把 ButtonBase 拖出來鞭屍了。

更新 ButtonBase 的理由是讓這個元件可以透過 props 傳入 ref 資料,而需要這樣做的理由是讓昨天的 Tooltip 元件可以不需要多一層 span 來包覆 props.children 內容,而是直接把用來計算 props.childrenref 貼到 child node 上。

原本的作法是多包一層 spanprops.children 外面,就不需要擔心 props.children 是否支援 props.ref

return (
  <React.Fragment>
    <span
      onMouseOver={() => setShow(true)}
      onMouseOut={() => setShow(false)}
      ref={childRef}
    >
      {children}
    </span>
    {shouldShow && (
      <Portal>
        <span className={cn(baseStyle, animationStyle, finalStyle)}>
          {arrow && <span className={cn(baseArrowStyle, positionArrowStyle)} />}
          {tip}
        </span>
      </Portal>
    )}
  </React.Fragment>
);

但是既然有找到辦法處理多重 refs 的需求,這個非必要的 span 當然就是要跟他說再見啦 (゚ ∀ ゚)

成品

原始碼
展示

開發思路

forward refs

套用 React.forwardRef 來處理即可,記得 ButtonBaseButton 元件都需要修改。可直接複製貼上今天的原始碼。

ref merge

參考 React 官方文件可得知元件的 props.ref 除了可以傳入 createRef()useRef() 建立的 MutableRefObject 以外,也能接受傳入 callback function:

Callback Refs: Instead of passing a ref attribute created by createRef(), you pass a function. The function receives the React component instance or HTML DOM element as its argument, which can be stored and accessed elsewhere.

把 callback function 傳入元件的 props.ref 時,該 function 接受元件實例(instance)或 HTML DOM 物件作為參數。

附上 stackOverFlow 上的說明:

Ref callbacks are another option, which are needed for some advanced cases. You pass a function into the element, and the function will be called back when the instance is created or destroyed. These have the type (instance: T) => void.

總結一下在 mergeRef 處理的事情:

return (node) => {
  refs.forEach((ref) => {
    if (typeof ref === 'function') {
      // 當 ref 為的型別為 function 時,把元件實例或 HTML DOM 作為參數傳入
      ref(node);
    } else if (ref !== null) {
      // 若 ref 不為 null 則把該元件的實例或 HTML DOM 物件指派給 MutableRefObject.current
      (ref as React.MutableRefObject<T | null>).current = node;
    }
  });
};

執行完畢後,透過 forwardRef 傳入的 ref 與元件本身的 local ref 都會指向同一個元件實例或 HTMLElement。

自評

在實作完今天的元件之前,沒有想過原來元件的 props.ref 支援傳入 callback,甚至還可以合併...(゚ ∀ ゚) 長知識了。

參考文件


上一篇
day23: Tooltip
下一篇
day25: Input
系列文
我們可以不要 component library 了嗎?30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言